/*
 * command.c
 *
 *  Created on: Mar 27, 2013
 *      Author: locpm
 */

#include <stdio.h>
#include <string.h>
#include "extglobals.h"
#include "protos.h"
#include "board.h"
#include "move.h"
#include "timer.h"
void readCommands()
{
	int nextc;

	if (board.nextMove == WHITE_MOVE)
	{
		printf("wt> ");
	}
	else
	{
		printf("bl> ");
	}

	//     ===========================================================================
	//     Read a command and call doCommand:
	//     ===========================================================================

	while ((nextc = getc(stdin)) != EOF)
	{
		if (nextc == '\n')
		{
			CMD_BUFF[CMD_BUFF_COUNT] = '\0';
			while (CMD_BUFF_COUNT)
			{
				if (!doCommand(CMD_BUFF)) return;
			}

			if (board.nextMove == WHITE_MOVE)
			{
				printf("wt> ");
			}
			else
			{
				printf("bl> ");
			}

		}
		else
		{
			if (CMD_BUFF_COUNT >= MAX_CMD_BUFF-1)
			{
				printf("Warning: command buffer full !! \n");
				CMD_BUFF_COUNT = 0;
			}
			CMD_BUFF[CMD_BUFF_COUNT++] = nextc;
		}
	}

	return;
}

BOOL doCommand(const char *buf)
{
	char userinput[MAX_CMD_BUFF];
	MOVE move;
	TIMER timer;
	U64 msStart;
	U64 msStop;
	U64 perftcount;
	int number;

	//     =================================================================
	//  return when command buffer is empty
	//     =================================================================

	if (!strcmp(buf, ""))
	{
		CMD_BUFF_COUNT = '\0';
		return TRUE;
	}

	//     =================================================================
	//  help, h, or ?: show this help
	//     =================================================================
	if ((!strcmp(buf, "help")) || (!strcmp(buf, "h")) || (!strcmp(buf, "?")))
	{
		printf("help:\n");
		printf("black               : BLACK to move\n");
		printf("cc                  : play computer-to-computer \n");
		printf("d                   : display board \n");
		printf("exit                : exit program \n");
		printf("eval                : show static evaluation of this position\n");
		printf("game                : show game moves \n");
		printf("go                  : computer next move \n");
		printf("help, h, or ?       : show this help \n");
		printf("info                : display variables (for testing purposes)\n");
		printf("move e2e4, or h7h8q : enter a move (use this format)\n");
		printf("moves               : show all legal moves\n");
		printf("new                 : start new game\n");
		printf("perf                : benchmark a number of key functions\n");
		printf("perft n             : calculate raw number of nodes from here, depth n \n");
		printf("quit                : exit program \n");
		printf("r                   : rotate board \n");
		printf("readfen filename n  : reads #-th FEN position from filename\n");
		printf("sd n                : set the search depth to n\n");
		printf("setup               : setup board... \n");
		printf("undo                : take back last move\n");
		printf("white               : WHITE to move\n");
		printf("\n");
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  exit or quit: exit program
	//     =================================================================
	if ((!strcmp(buf, "exit")) || (!strcmp(buf, "quit")))
	{
		CMD_BUFF_COUNT = 0;
		return FALSE;
	}

	//     =================================================================
	//  d: display board
	//     =================================================================
	if (!strcmp(buf, "d"))
	{
		displayBoard(board);
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  black: black to move
	//     =================================================================
	if (!strcmp(buf, "black"))
	{
		board.nextMove = BLACK_MOVE;
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  white: white to move
	//     =================================================================
	if (!strcmp(buf, "white"))
	{
		board.nextMove = WHITE_MOVE;
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}


	//     =================================================================
	//  r: rotate board
	//     =================================================================
	if (!strcmp(buf, "r"))
	{
		board.viewRotated = !board.viewRotated;
		displayBoard(board);
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//	=================================================================
	//  moves: show all legal moves
	//	=================================================================
	if (!strcmp(buf, "moves"))
	{
		board.moveBufLen[0] = 0;
		int i;

		board.moveBufLen[1] = movegen(board.moveBufLen[0]);

		printf("pseudo-legal moves from this position:\n");
		for (i = board.moveBufLen[0]; i < board.moveBufLen[1]; i++)
		{
			printf("%d. ", i+1);
			displayMove(board.moveBuffer[i]);
			printf("\n");
		}
		CMD_BUFF_COUNT = 0;

		return TRUE;
	}


	//	=================================================================
	//  move (do a move) [console mode only]
	//	=================================================================

	if (!strncmp(buf, "move", 4))
	{
		sscanf(buf + 4, "%s", userinput);

		// generate the pseudo-legal move list
		board.moveBufLen[0] = 0;
		board.moveBufLen[1] = movegen(board.moveBufLen[0]);

		// check to see if the user move is also found in the pseudo-legal move list
		if (isValidTextMove(userinput, &move))
		{
			makeMove(move);

			// post-move check to see if two kings face to face directly
			if (isTwoKingsFaceToFace())
			{
				unMakeMove(move);
				printf("invalid move, two kings face to face directly: %s\n", userinput);
			}
			// post-move check to see if we are leaving our king in check
			else if (isOtherKingAttacked())
			{
				unMakeMove(move);
				printf("invalid move, leaving king in check: %s\n", userinput);
			}
			else
			{
				board.endOfGame++;
				board.endOfSearch = board.endOfGame;
				displayBoard(board);
			}
		}
		else
		{
			printf("move is invalid or not recognized: %s\n", userinput);
		}

		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  undo: take back last move
	//     =================================================================
	if (!strcmp(buf, "undo"))
	{
		if (board.endOfGame)
		{
			unMakeMove(board.gameLine[--board.endOfGame].move);
			board.endOfSearch = board.endOfGame;
			displayBoard(board);
		}
		else
			printf("already at start of game\n");

		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  sd n: set the search depth to n
	//     =================================================================
	if (!strncmp(buf, "sd", 2))
	{
		sscanf(buf + 2, "%d", &board.searchDepth);
		printf("search depth is set to %d\n", board.searchDepth);

		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  go: computer next move
	//     =================================================================
	if (!strcmp(buf, "go"))
	{
		move = think();
		if (move.moveInt)
		{
			makeMove(move);
			board.endOfGame++;
			board.endOfSearch = board.endOfGame;
			displayBoard(board);
		}

		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	// =================================================================
	// perft n  : calculate raw number of nodes from here, depth n
	// =================================================================

	if (!strncmp(buf, "perft", 5))
	{
		sscanf(buf+5,"%d", &number);
		printf("    starting perft %d...\n", number);

		initTimer(&timer);
		board.moveBufLen[0] = 0;

		msStart = getMSTimer(&timer);
		perftcount = perft(0, number);
		msStop = getMSTimer(&timer);

		printf("nodes        = %"PRINTF_INT64_MODIFIER"u, %"PRINTF_INT64_MODIFIER"u ms, ", perftcount, msStop - msStart);

		if ((msStop - msStart) > 0)
			printf("%"PRINTF_INT64_MODIFIER"u  knods/s", perftcount/(msStop - msStart));
		printf("\n");

		CMD_BUFF_COUNT = 0;

		return TRUE;
	}

	//     =================================================================
	//  unknown command
	//     =================================================================
	printf("    command not implemented: %s, type 'help' for more info\n", buf);
	CMD_BUFF_COUNT = 0;
	return TRUE;
}
